package org.stvd.service.workflow.impl;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.impl.RepositoryServiceImpl;
import org.activiti.engine.impl.bpmn.behavior.UserTaskActivityBehavior;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.PvmTransition;
import org.activiti.engine.impl.pvm.delegate.ActivityBehavior;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.impl.pvm.process.TransitionImpl;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.IdentityLink;
import org.activiti.engine.task.Task;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.stvd.core.util.StringUtil;
import org.stvd.service.workflow.ProcessCoreService;
import org.stvd.service.workflow.WorkflowTraceService;

/**
 * 工作流跟踪相关Service
 *
 * @author HenryYan
 */
@Service
public class WorkflowTraceServiceImpl implements WorkflowTraceService {

    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    protected RuntimeService runtimeService;

    @Autowired
    protected TaskService taskService;

    @Autowired
    protected RepositoryService repositoryService;

    @Autowired
    protected IdentityService identityService;

    @Autowired
    protected HistoryService historyService;

    @Autowired
    ProcessCoreService processCoreService;

    @Autowired
    ProcessEngine processEngine;

    /**
     * 流程跟踪图
     * @param processInstanceId  流程实例ID
     * @return 封装了各种节点信息
     */
    public List<Map<String, Object>> traceProcess(String processInstanceId) throws Exception {
        Execution execution = runtimeService.createExecutionQuery().executionId(processInstanceId).singleResult();// 执行实例

        String activityId = "";
        List<Map<String, Object>> activityInfos = new ArrayList<Map<String, Object>>();

        if (execution != null) {
            Object property = PropertyUtils.getProperty(execution, "activityId");

            if (property != null) {
                activityId = property.toString();
            }
        }

        Object processInstance = null;
        String processDefinitionId = null;
        processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        if (processInstance == null) {
            processInstance = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processInstanceId).singleResult();
        }
        if (processInstance != null) {
            if(processInstance instanceof ProcessInstance){
                processDefinitionId = ((ProcessInstance)processInstance).getProcessDefinitionId();
            } else if(processInstance instanceof HistoricProcessInstance){ 
                processDefinitionId = ((HistoricProcessInstance)processInstance).getProcessDefinitionId();
            }
            
            ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService)
                    .getDeployedProcessDefinition(processDefinitionId);
            List<ActivityImpl> activitiList = processDefinition.getActivities();// 获得当前任务的所有节点

            // 历史节点
            List<HistoricActivityInstance> hisList = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId).list();

            for (ActivityImpl activity : activitiList) {

                boolean currentActiviti = false;
                String id = activity.getId();

                // 当前节点
                if (id.equals(activityId)) {
                    currentActiviti = true;
                }

                Map<String, Object> activityImageInfo = packageSingleActivitiInfo(hisList, activity, processInstance,
                        currentActiviti);

                activityInfos.add(activityImageInfo);
            }
        }
        return activityInfos;
    }

    /**
     * 封装输出信息，包括：当前节点的X、Y坐标、变量信息、任务类型、任务描述
     *
     * @param activity
     * @param processInstance
     * @param currentActiviti
     * @return
     */
    private Map<String, Object> packageSingleActivitiInfo(List<HistoricActivityInstance> hisList, ActivityImpl activity,
            Object processInstance, boolean currentActiviti) throws Exception {

        Map<String, Object> vars = new HashMap<String, Object>();
        Map<String, Object> activityInfo = new HashMap<String, Object>();
        activityInfo.put("currentActiviti", currentActiviti);

        setPosition(activity, activityInfo);
        setWidthAndHeight(activity, activityInfo);
        setLinePosition(hisList, activity, activityInfo);

        Map<String, Object> properties = activity.getProperties();
//        vars.put("任务类型", WorkflowUtils.parseToZhType(properties.get("type").toString()));
        if(properties.get("name") != null){
            vars.put("任务名称", properties.get("name").toString());
        }

        activityInfo.put("type", properties.get("type").toString());

        activityInfo.put("historyActiviti", false);
        for (HistoricActivityInstance historicActivityInstance : hisList) {
            if (historicActivityInstance.getActivityId().equals(activity.getId())) {
                vars.put("办理人员", historicActivityInstance.getAssignee());
                activityInfo.put("historyActiviti", true);
            }
        }

        ActivityBehavior activityBehavior = activity.getActivityBehavior();
        logger.debug("activityBehavior={}", activityBehavior);
        if (activityBehavior instanceof UserTaskActivityBehavior) {

            Task currentTask = null;
            /*
             * 当前节点的task
             */
            if (currentActiviti && processInstance instanceof ProcessInstance) {
                currentTask = getCurrentTaskInfo((ProcessInstance)processInstance);
            }

            // 当前处理人
             if (currentTask != null) {
                 setCurrentTaskAssignee(vars, (TaskEntity)currentTask);
             }

            /*
             * 当前任务的分配角色
             */
//            UserTaskActivityBehavior userTaskActivityBehavior = (UserTaskActivityBehavior) activityBehavior;
//            TaskDefinition taskDefinition = userTaskActivityBehavior.getTaskDefinition();
//            Set<Expression> candidateGroupIdExpressions = taskDefinition.getCandidateGroupIdExpressions();
//            if (!candidateGroupIdExpressions.isEmpty()) {

                // 任务的处理角色
                // setTaskGroup(vars, candidateGroupIdExpressions);
//            }
        }

        vars.put("节点说明", properties.get("documentation"));

        String description = activity.getProcessDefinition().getDescription();
        vars.put("描述", description);

        logger.debug("trace variables: {}", vars);
        activityInfo.put("vars", vars);
        return activityInfo;
    }

    private void setTaskGroup(Map<String, Object> vars, Set<Expression> candidateGroupIdExpressions) {
        String roles = "";
        for (Expression expression : candidateGroupIdExpressions) {
            String expressionText = expression.getExpressionText();
            String roleName = identityService.createGroupQuery().groupId(expressionText).singleResult().getName();
            roles += roleName;
        }
        vars.put("任务所属角色", roles);
    }

    /**
     * 设置当前处理人信息
     *
     * @param vars
     * @param currentTask
     */
    private void setCurrentTaskAssignee(Map<String, Object> vars, TaskEntity currentTask) {
        String assignee = currentTask.getAssignee();
        if (assignee != null) {
//            User assigneeUser = identityService.createUserQuery().userId(assignee).singleResult();
//            String userInfo = assigneeUser.getFirstName() + " " + assigneeUser.getLastName();
//            vars.put("当前处理人", userInfo);
            vars.put("当前办理", assignee);
        } else {
            String candidate = "";
            String groupIds = "";
            for (IdentityLink identityLink : taskService.getIdentityLinksForTask(currentTask.getId())){
                if(!StringUtil.isEmpty(identityLink.getUserId())){
                    candidate += ","+identityLink.getUserId();
                }
                if(!StringUtil.isEmpty(identityLink.getGroupId())){
                    groupIds += ","+identityLink.getGroupId();
                }
            }
            if(!StringUtil.isEmpty(candidate)){
                candidate = candidate.substring(1);
                vars.put("当前办理", candidate);
            }
            if(!StringUtil.isEmpty(groupIds)){
                groupIds = groupIds.substring(1);
                vars.put("当前办理", groupIds);
            }
        }
    }

    /**
     * 获取当前节点信息
     *
     * @param processInstance
     * @return
     */
    private Task getCurrentTaskInfo(ProcessInstance processInstance) {
        Task currentTask = null;
        try {
            String activitiId = (String) PropertyUtils.getProperty(processInstance, "activityId");
            logger.debug("current activity id: {}", activitiId);

            currentTask = taskService.createTaskQuery().processInstanceId(processInstance.getId())
                    .taskDefinitionKey(activitiId).singleResult();
            logger.debug("current task for processInstance: {}", ToStringBuilder.reflectionToString(currentTask));

        } catch (Exception e) {
            logger.error("can not get property activityId from processInstance: {}", processInstance);
        }
        return currentTask;
    }

    public List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinitionEntity,
            List<HistoricActivityInstance> historicActivityInstances) {
        List<String> highFlows = new ArrayList<String>();// 用以保存高亮的线flowId
        for (int i = 0; i < historicActivityInstances.size() - 1; i++) {// 对历史流程节点进行遍历
            ActivityImpl activityImpl = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i).getActivityId());
            // 得到节点定义的详细 信息
            List<ActivityImpl> sameStartTimeNodes = new ArrayList<ActivityImpl>();
            // 用以保存后需开始时间相同的节点
            ActivityImpl sameActivityImpl1 = processDefinitionEntity
                    .findActivity(historicActivityInstances.get(i + 1).getActivityId());
            // 将后面第一个节点放在时间相同节点的集合里
            sameStartTimeNodes.add(sameActivityImpl1);
            for (int j = i + 1; j < historicActivityInstances.size() - 1; j++) {
                HistoricActivityInstance activityImpl1 = historicActivityInstances.get(j);// 后续第一个节点
                HistoricActivityInstance activityImpl2 = historicActivityInstances.get(j + 1);// 后续第二个节点
                if (activityImpl1.getStartTime().equals(activityImpl2.getStartTime())) {// 如果第一个节点和第二个节点开始时间相同保存
                    ActivityImpl sameActivityImpl2 = processDefinitionEntity
                            .findActivity(activityImpl2.getActivityId());
                    sameStartTimeNodes.add(sameActivityImpl2);
                } else {// 有不相同跳出循环
                    break;
                }
            }
            List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();// 取出节点的所有出去的线

            for (PvmTransition pvmTransition : pvmTransitions) {// 对所有的线进行遍历
                ActivityImpl pvmActivityImpl = (ActivityImpl) pvmTransition.getDestination();
                // 如果取出的线的目标节点存在时间相同的节点里，保存该线的id，进行高亮显示
                if (sameStartTimeNodes.contains(pvmActivityImpl)) {
                    highFlows.add(pvmTransition.getId());
                }
            }
        }
        return highFlows;
    }

    /**
     * 设置宽度、高度属性
     *
     * @param activity
     * @param activityInfo
     */
    private void setWidthAndHeight(ActivityImpl activity, Map<String, Object> activityInfo) {
        activityInfo.put("width", activity.getWidth());
        activityInfo.put("height", activity.getHeight());
    }

    /**
     * 设置坐标位置
     *
     * @param activity
     * @param activityInfo
     */
    private void setPosition(ActivityImpl activity, Map<String, Object> activityInfo) {
        activityInfo.put("x", activity.getX());
        activityInfo.put("y", activity.getY());
    }

    /**
     * 设置连接线的坐标，一个连接线至少有4个数值，成对组成xy坐标值，例如[x1,y1,x2,y2,x3,y3,......],
     * 一个连接线如果是直线，则有2个点，如果有折现，则可能是2个以上的点
     * 
     * @param hisList
     *            执行过的历史节点
     * @param activity
     *            当前节点
     * @param activityInfo
     */
    private void setLinePosition(List<HistoricActivityInstance> hisList, ActivityImpl activity,
            Map<String, Object> activityInfo) {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        for (PvmTransition sequenceFlow : activity.getIncomingTransitions()) {
            for (HistoricActivityInstance historicActivityInstance : hisList) {
                if (historicActivityInstance.getActivityId().equals(sequenceFlow.getSource().getId())) {
                    List<Integer> waypoints = ((TransitionImpl) sequenceFlow).getWaypoints();
                    list.add(waypoints);
                }
            }
        }
        activityInfo.put("linePos", list);
    }
}
